package model;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AppModel {

	private WordModel currentWord;
	private LinkedList<WordModel> words;
	private int wordsAttempted;
	private float currentTestMark;
	private int wordsLeft;
	private boolean started;
	private boolean finished;
	private boolean polishToForeignMode;
	private int numberOfLastLoadedWords;
	
	private static final String[] ACCENTS_A = {"a", "\u00E1"};
	private static final String[] ACCENTS_E = {"e", "\u00E9"};
	private static final String[] ACCENTS_I = {"i", "\u00ED"};
	private static final String[] ACCENTS_O = {"o", "\u00F3"};
	private static final String[] ACCENTS_U = {"u", "\u00FA"};
	private static final String[] ACCENTS_N = {"n", "\u00F1"};

	private String[][] accents = {ACCENTS_A, ACCENTS_E, ACCENTS_I, ACCENTS_O, ACCENTS_U, ACCENTS_N};

	public AppModel()
	{
		clearWordsResetFlagsMarksMode();
		polishToForeignMode = true;
	}
	
	public boolean isPolishToForeignMode()
	{
		return polishToForeignMode;
	}
	
	public String[][] getAccents() {
		return accents;
	}
	
	public void clearWordsResetFlagsMarksMode()
	{
		words = new LinkedList<WordModel>();
		resetFlagsMarksMode();
	}
	
	public boolean isStarted() {
		return started;
	}
	
	public void revertMode()
	{
		if(areWordsLoaded())
		{
			polishToForeignMode = !polishToForeignMode;
			for(WordModel wm : words)
			{
				wm.revertMode();
			}
		}
	}
	
	private void resetFlagsMarksMode()
	{
		this.finished = false;
		this.started = false;
		wordsAttempted = 0;
		currentTestMark = 0;
		this.wordsLeft = this.getNumberOfWords();
	}
	
	private void setWordsUnusedAndShuffle()
	{
		for(WordModel wm : words)
		{
			wm.setUnused();
			wm.setMark(0);
		}
		Collections.shuffle(words);
	}

	public void start()
	{
		if(areWordsLoaded())
		{
			setWordsUnusedAndShuffle();
			resetFlagsMarksMode();
			this.started = true;
			nextWord();
		}
	}

	public boolean areWordsLoaded()
	{
		return this.getNumberOfWords() > 0;
	}
	
	public int getNumberOfLastLoadedWords() {
		return numberOfLastLoadedWords;
	}

	public boolean setUpWords(File[] filesList)
	{
		numberOfLastLoadedWords = 0;
		File f = null;
		for(int i = 0; i < filesList.length; i++ )
		{
			f = filesList[i];
			readWordsFromFile(f);
		}

		Collections.shuffle(words);
		return true;
	}
	
	private void readWordsFromFile(File file)
	{
        Scanner sc = null;
        try {
			sc = new Scanner(file, "UTF-8");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        sc.useDelimiter("[;\r\n]+");
        WordModel w = null;
        while(sc.hasNext())
        {
        	String wordPolish = sc.next().toLowerCase().trim();
        	if(wordPolish.startsWith("//"))
        	{
        		sc.next();
        		sc.next();
        		sc.next();
        		continue;
        	}
        	String wordForeign = sc.next().toLowerCase().trim();
        	w = new WordModel(wordPolish, wordForeign, polishToForeignMode);
        	String sentencePolish = sc.next().trim();
        	String sentenceForeign = sc.next().trim();
        	if (sentencePolish != null && !sentencePolish.equals("") && !sentencePolish.equals("x") && sentenceForeign != null && !sentenceForeign.equals("") && !sentenceForeign.equals("x")) {
        		w.setSentences(sentencePolish, sentenceForeign);
        	}
    		words.add(w);
    		numberOfLastLoadedWords++;
        }
        sc.close();
	}
	
	public WordModel getCurrentWord()
	{
		return currentWord;
	}
	
	public boolean isUsed()
	{
		return currentWord.isUsed();
	}
	
	public void nextWord()
	{
		WordModel w = words.removeFirst();
		currentWord = w;
		words.addLast(w);
		wordsLeft--;
		if(currentWord.isUsed())
		{
			finished = true;
			started = false;
		}
	}
	
	public boolean isFinished() {
		return finished;
	}

	public boolean checkAnswer(String userAnswer)
	{
		currentWord.setUsed();
		userAnswer = userAnswer.toLowerCase().trim();
		boolean isPerfect = validate(userAnswer);
		wordsAttempted++;
		currentTestMark += currentWord.getMark();
		return isPerfect;
	}
	
	private boolean validate(String userAnswer)
	{
		return compareAnswersSetMark(currentWord.getCorrect(), userAnswer);
	}

	private boolean compareAnswersSetMark(String correct, String userAnswer)
	{
//		System.out.print("correct=");for(int i = 0; i<correct.getBytes().length;i++){System.out.print(correct.getBytes()[i]+"-");}System.out.println();
//		System.out.print("userAnswer=");for(int i = 0; i<userAnswer.getBytes().length;i++){System.out.print(userAnswer.getBytes()[i]+"-");}System.out.println();
		if (correct.equals(userAnswer))
		{
			return correct();
		}
		else if (userAnswer.equals(""))
		{
			currentWord.setMark(0);
		}
		else if (ifCorrectApartFromPrefix(correct, userAnswer))
		{
			currentWord.setMark(0.5F);
		}
		else
		{
			if(matchesOneOfDefinitions(correct, userAnswer))
			{
				return correct();
			}
			
			ifOnlyAccentMistakes(correct, userAnswer);
			
//			char[] correctArray = correct.toCharArray();
//			char[] userAnswerArray = userAnswer.toCharArray();
//			System.out.println("character arrays");
//
//			System.out.println(correctArray);
//			System.out.println(userAnswerArray);
		}
		return false;
	}
	
	private boolean ifCorrectApartFromPrefix(String correct, String userAnswer)
	{
		return correct.replaceFirst(getRegex(), "").equals(userAnswer.replaceFirst(getRegex(), ""));
	}
	
	private boolean matchesOneOfDefinitions(String correct, String userAnswer)
	{
		String[] words = correct.split(",");
		for(int i = 0; i < words.length; i++)
		{
			String currentCorrectPart = words[i].trim();
			if (currentCorrectPart.equals(userAnswer))
			{
				return true;
			}
		}
		return false;
	}
	
	private void ifOnlyAccentMistakes(String correct, String userAnswer)
	{
		if (userAnswer.length() == correct.length())
		{
			Pattern pattern = Pattern.compile(getRegex());
			Matcher matcherUser = pattern.matcher(userAnswer);
			Matcher matcherCorrect = pattern.matcher(correct);
			if(matcherUser.find() && matcherCorrect.find())
			{
				String m1 = matcherUser.group();
				String m2 = matcherCorrect.group();
				if (m1 != null && m2 != null && m1.equals(m2))
				{
					loop:
					for(int j = 0; j < correct.length(); j++)
					{
						String c = String.valueOf(correct.charAt(j));
						for(int i = 0; i < accents.length; i++)
						{
							final String spanishLetter = accents[i][1];
							if(spanishLetter.equals(c))
							{
								final String keyboardLetter = accents[i][0];
								String u = String.valueOf(userAnswer.charAt(j));
								if (!c.equals(u) && !keyboardLetter.equals(u))
								{
									currentWord.setMark(0);
									break loop;
								}
							}
						}
					}
					currentWord.setMark(0.5F);
				}
			}
		}
	}
	
	private String getRegex()
	{
		return "(el|la|los|las) ";
	}
	
	private boolean correct()
	{
		currentWord.setMark(1);
		return true;
	}
	
	public int getNumberOfWords()
	{
		int response = 0;
		if (this.words != null) {
			response = words.size();
		}
		return response;
	}
	
	public float getQuestionMark()
	{
		return currentWord.getMark();
	}
	
	public int getWordsLeft() {
		return wordsLeft;
	}

	public String getTestMarks()
	{
		if(wordsAttempted == 0)
		{
			return "0/0";
		}
		int prc = (int) (currentTestMark * 100 / wordsAttempted);
		return this.currentTestMark + "/" + this.wordsAttempted + " ("+prc+"%)";
	}

	@Override
	public String toString() {
		return "AppModel [currentWord=" + currentWord + ", wordsAttempted="
				+ wordsAttempted + ", currentTestMark=" + currentTestMark
				+ ", wordsLeft=" + wordsLeft + ", started=" + started
				+ ", finished=" + finished + ", polishToForeignMode="
				+ polishToForeignMode + ", numberOfLastLoadedWords="
				+ numberOfLastLoadedWords + "]";
	}
}